/* * TMP Animation JS * (c) 2025 Themes-Park * Released under the themes-park.net */ // Class names for different scroll and animation states const TMP_SCROLL_ACTIVATION = "tmp-scroll-trigger"; TMP_SCROLL_OFFSCREEN_ACTIVATION = "tmp-scroll-trigger--offscreen", TMP_SCROLL_ZOOM_IN_ACTIVATION = "animate--zoom-in", TMP_SCROLL_CANCEL_ACTIVATION = "tmp-scroll-trigger--cancel"; // Handle intersection events for scroll animations function onIntersection(entries, observer) { entries.forEach((entry, index) => { if (entry.isIntersecting) { const elementTarget = entry.target; if ($(elementTarget).hasClass(TMP_SCROLL_OFFSCREEN_ACTIVATION)) { $(elementTarget).removeClass(TMP_SCROLL_OFFSCREEN_ACTIVATION); if ($(elementTarget).attr("data-cascade")) { $(elementTarget).css("--animation-order", index); } } observer.unobserve(elementTarget); } else { $(entry.target).addClass(TMP_SCROLL_OFFSCREEN_ACTIVATION); $(entry.target).removeClass(TMP_SCROLL_CANCEL_ACTIVATION); } }); } // Initialize scroll animation triggers function initializeScrollAnimationTrigger(rootEl = document, isDesignModeEvent = false) { const animationTriggerElements = $(rootEl).find(`.${TMP_SCROLL_ACTIVATION}`); if (animationTriggerElements.length === 0) return; if (isDesignModeEvent) { animationTriggerElements.each(function() { $(this).addClass("tmp-scroll-trigger--design-mode"); }); return; } const observer = new IntersectionObserver(onIntersection, { rootMargin: "0px 0px -50px 0px" }); animationTriggerElements.each(function() { observer.observe(this); }); } // Initialize zoom-in animation triggers function initializeScrollZoomAnimationTrigger() { if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return; const animationTriggerElements = $(`.${TMP_SCROLL_ZOOM_IN_ACTIVATION}`); if (animationTriggerElements.length === 0) return; const scaleAmount = 0.2 / 100; animationTriggerElements.each(function() { const element = this; let elementIsVisible = false; new IntersectionObserver(entries => { entries.forEach(entry => { elementIsVisible = entry.isIntersecting; }); }).observe(element); $(element).css("--zoom-in-ratio", 1 + scaleAmount * percentageSeen(element)); $(window).on("scroll", throttle(() => { if (elementIsVisible) { $(element).css("--zoom-in-ratio", 1 + scaleAmount * percentageSeen(element)); } }, 100), { passive: true }); }); } // Calculate the percentage of the element that is visible function percentageSeen(element) { const viewportHeight = window.innerHeight, scrollY = window.scrollY, elementPositionY = $(element).offset().top, elementHeight = $(element).outerHeight(); if (elementPositionY > scrollY + viewportHeight) return 0; if (elementPositionY + elementHeight < scrollY) return 100; let percentage = (scrollY + viewportHeight - elementPositionY) / ((viewportHeight + elementHeight) / 100); return Math.round(percentage); } // Initialize animations and remove initial opacity class from swiper slides $(document).ready(() => { $(".swiper-slide.opacity-0").each(function() { $(this).removeClass("opacity-0"); }); initializeScrollAnimationTrigger(); initializeScrollZoomAnimationTrigger(); }); // Throttle the scroll event to improve performance function throttle(fn, wait) { let time = Date.now(); return function() { if ((time + wait - Date.now()) < 0) { fn(); time = Date.now(); } } }